#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include <list>
#include <mutex>
#include  "serial.h"
#include  "timeout.h"
#include "parsedata.h"

using namespace std;
	char serial::Open(char* port, int baud, char bits, parity parity, char stopbit) 
	{
		char tmp[BUFFER_SIZE];
		
		// Convert to string
		sprintf(tmp, "%s", port);
		//cout<<"start open"<<endl;
   		m_fd = open(tmp, O_RDONLY);
		
		// Check opening status 
		if (m_fd < 0)
		{
	        printf("Error Opening %s Port\n", tmp);
	        return 0;
		}
		
		// Get terminal parameters
		tcgetattr(m_fd, &m_newtio);
		tcgetattr(m_fd, &m_oldtio);

		// Flushes data received but not read		
		ioctl(m_fd, TCIFLUSH);

		// Set baud rate (in and out)
		switch(baud)
		{
			case 9600	: cfsetspeed(&m_newtio, B9600)	; break;
			case 19200	: cfsetspeed(&m_newtio, B19200)	; break;
			case 38400	: cfsetspeed(&m_newtio, B38400)	; break;
			case 57600	: cfsetspeed(&m_newtio, B57600)	; break;
			case 115200	: cfsetspeed(&m_newtio, B115200); break;
			default 	: cfsetspeed(&m_newtio, B9600)	; break;
		}

		// Set byte size
		m_newtio.c_cflag &= ~CSIZE;	

		switch(bits)
		{
			case 5	: m_newtio.c_cflag |= CS5; break;
			case 6	: m_newtio.c_cflag |= CS6; break;
			case 7	: m_newtio.c_cflag |= CS7; break;
			case 8	: m_newtio.c_cflag |= CS8; break;
			default : m_newtio.c_cflag |= CS8; break;
		}

		// Set parity
		switch(parity)
		{
			case NO	  :
					m_newtio.c_cflag &=~ PARENB;	// Disable parity
				break;
				
			case EVEN :
					m_newtio.c_cflag |= PARENB;		// Enable parity
					m_newtio.c_cflag &= ~PARODD;	// Disable odd parity
				break;
				
			case ODD  :
					m_newtio.c_cflag |= PARENB;		// Enable parity
					m_newtio.c_cflag |= PARODD;		// Enable odd parity
				break;
				
			default	  :
					m_newtio.c_cflag &=~ PARENB;	// Disable parity
		}
		
		// Set stop bit
		switch(stopbit)
		{
			case 1: m_newtio.c_cflag &=~ CSTOPB	; break;	// Disable 2 stop bits
			case 2: m_newtio.c_cflag |= CSTOPB	; break;	// Enable 2 stop bits
			default: m_newtio.c_cflag &=~ CSTOPB;
		}
	
		// Enable receiver (CREAD) and ignore modem control lines (CLOCAL)
		m_newtio.c_cflag |= (CREAD | CLOCAL); 
		
		// Disable, canonical mode (ICANON = 0), echo input character (ECHO) and signal generation (ISIG)
		m_newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 
		
		// Disable input parity checking (INPCK)
		m_newtio.c_iflag &= ~INPCK; 		  
	
		// Disable XON/XOFF flow control on output and input (IXON/IXOFF), framing and parity errors (IGNPAR), and disable CR to NL translation
		m_newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR | ICRNL);
	
		// Disable implementation-defined output processing (OPOST)
		m_newtio.c_oflag &=~ OPOST;	

		// Set terminal parameters
		tcsetattr(m_fd, TCSAFLUSH, &m_newtio);
		
		// Display settings
		printf("%s | BaudRate: %d | Bits: %d | Parity: %d | StopBits: %d\n", tmp, baud, bits, parity, stopbit);
	
		return 1;
	}
	
	void serial::Close(void) 
	{
   		// Set old parameters
		tcsetattr(m_fd, TCSANOW, &m_oldtio);
   		
   		// Close serial port
		if(m_fd > 0)
		{
			close(m_fd);
		}
	}
	
	
	char serial::Write(char* buffer, int length) 
	{
		ssize_t r;
		const uint8_t *pos = (const uint8_t*)buffer;

		// Send data
		while(length > 0)
		{
			r = write(m_fd, pos, length);
			
			if(r < 1)
			{
				return 0;
			}

			length -= r;
			pos += r;
		}

		return 1;
	}
	
	int serial::Read(char* buffer)
	{
		ssize_t r = 1;
		int length = 0;

		// Set timeout between 2 bytes (20ms)
		timeout timeout(TIME_OUT);
		
		//memset(buffer, 0x00, BUFFER_SIZE);
		
		while((r > 0) || timeout.end())
		{
			// Protect buffer
			if(length >= (BUFFER_SIZE - 1)) return length;
			
			r = read(m_fd, (buffer + length), 1);
						
			if(r > 0)
			{
				length++;

				// Start timer
				timeout.start();
			}
		}
		
		return length;
	}
	list<CPT> hugeListBuffer;
	mutex m;

	//  线程体，不断地读取数据
	void *parsedataFunction(void *arg)
	{
		std::cout<<"ReadFunction"<<std::endl;
		serial serial;

		char buffer[104] = {0};
		int i, length = 0;
		ParseData  pd;
		char* ch = (char*)"/dev/ttyS1";
		std::cout<<ch<<std::endl;
		serial.Open(ch, 115200, 8, NO, 1);
		std::vector<u_int8_t>  strRecv;
		while(1)
		{
			usleep(1);
			// Wait character
			length = serial.Read(buffer);
			if(length)
			{
				for(i = 0; i < length; i++)
				{				
					strRecv.push_back(buffer[i]);
				}
				m.lock();
				pd.ljlparse_data(strRecv,hugeListBuffer);
				m.unlock();
			}
		}
	// Close serial port
	serial.Close();	
	}

	void *writeFileFunction(void *arg)
	{
		std::cout<<"writeFileFunction"<<std::endl;
		int i, length = 0;
		string str1;
		ofstream ofs;
		time_t now = time(0);
		tm *ltm = localtime(&now);
		string rtime = 
						to_string(1900+ltm->tm_year)+"_"+
						to_string(1+ltm->tm_mon)+"_"+
						to_string(ltm->tm_mday)+"_"+
						to_string(ltm->tm_hour)+"_"+
						to_string(ltm->tm_min/10);
		str1 = "imu_data_"+rtime+".txt";
		ofs.open(str1,ios::app);
		while(1)
		{	
			usleep(20);
			// Wait character
			CPT ljlCPT_imu;
			if(hugeListBuffer.size()>0){
					m.lock();
					ljlCPT_imu=hugeListBuffer.front();
					hugeListBuffer.pop_front();
					m.unlock();
					//@ljl 写入文件的速度比读取要慢
					ofs << ljlCPT_imu.utime<<" ";	
					ofs << ljlCPT_imu.azimuth<<" "; 
					ofs << ljlCPT_imu.roll<<" "; 
					ofs << ljlCPT_imu.pitch <<" "; 
					ofs << ljlCPT_imu.latitude<<" " ; 											
					ofs << ljlCPT_imu.longitude<<" "; 
					ofs << ljlCPT_imu.altitude<<" "; 
					ofs << ljlCPT_imu.northVelocity<<" "; 
					ofs << ljlCPT_imu.eastVelocity<<" "; 
					ofs << ljlCPT_imu.upVelocity<< endl; 
					
				}
		}
		ofs.close();	
	}

	// 开启读线程
	void serial::StartRead()
	{
		
		pthread_t parsedataThread;
		pthread_t writeToFileThread;

		std::cout<<"you create a parsedataThread!!"<<std::endl;
		if ( pthread_create( &parsedataThread, NULL, parsedataFunction, NULL) ) 
		{
			printf("Error creating readThread.\n");
		}

		std::cout<<"you create a writeToFileThread!!"<<std::endl;
		if ( pthread_create( &writeToFileThread, NULL, writeFileFunction, NULL) ) 
		{
			printf("Error creating readThread.\n");
		}
	}
